package com.blue.core.auth;

import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * AES加解类工具类（AES/CBC/NoPadding）
 * 
 * @author zhengj
 * @since 1.0
 * @date 2012-11-14
 */
public class AESUtil
{
	private static Logger logger = LoggerFactory.getLogger(AESUtil.class);

	private static final String KEY_ALGORITHM = "AES";
	// 算法/模式/补码方式
	private static final String CIPHER_ALGORITHM = "AES/CBC/NoPadding";
	//private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
	// private static final int KEY_SIZE = 128;

	private AESUtil()
	{
	}

	/**
	 * 小数据量加密，返回Base64编码字符串
	 * 
	 * @param password AES加密密钥
	 * @param raw 明文
	 * @return 密文，Base64编码
	 */
	public static String encrypt(String password, String data)
	{
		String raw = null;
		byte[] keys = DigestUtil.md5(password);
		try
		{
			byte[] dataBytes = data.getBytes("UTF-8");
			Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);

			if (CIPHER_ALGORITHM.endsWith("NoPadding")) // 需要补0
			{
				int blockSize = cipher.getBlockSize();
				int plaintextLength = dataBytes.length;
				if (plaintextLength % blockSize != 0)
				{
					plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
				}
				byte[] plaintext = new byte[plaintextLength];
				System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
				//logger.info("原始长度：{}，补0后长度：{}", dataBytes.length, plaintext.length);
				dataBytes = plaintext;
			}

			SecretKeySpec keySpec = new SecretKeySpec(keys, KEY_ALGORITHM);
			IvParameterSpec ivSpec = new IvParameterSpec(keys);

			cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
			byte[] tmp = cipher.doFinal(dataBytes);

			raw = Base64.getEncoder().encodeToString(tmp);
		}
		catch (Exception e)
		{
			logger.error("AES加密失败", e);
		}
		return raw;
	}

	/**
	 * 小数据量解密
	 * 
	 * @param password AES加密密钥
	 * @param raw 密文，Base64编码
	 * @return 明文
	 */
	public static String decrypt(String password, String raw)
	{
		String data = null;
		byte[] rawBytes = Base64.getDecoder().decode(raw);
		byte[] keys = DigestUtil.md5(password);
		try
		{
			SecretKeySpec keySpec = new SecretKeySpec(keys, KEY_ALGORITHM);
			IvParameterSpec ivSpec = new IvParameterSpec(keys);

			Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
			cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
			byte[] dataBytes = cipher.doFinal(rawBytes);

			if (CIPHER_ALGORITHM.endsWith("NoPadding")) // 需要去除0
			{
				int n = 0;
				for (int i = dataBytes.length - 1; i >= 0; i--)
				{
					if (dataBytes[i] != 0)
						break;

					n++;
				}
				//logger.info("末尾0个数：{}", n);
				byte[] plaintext = new byte[dataBytes.length - n];
				System.arraycopy(dataBytes, 0, plaintext, 0, plaintext.length);
				//logger.info("原始长度：{}，去0后长度：{}", dataBytes.length, plaintext.length);
				dataBytes = plaintext;
			}

			data = new String(dataBytes, "UTF-8");
		}
		catch (Exception e)
		{
			logger.error("AES解密失败", e);
		}
		return data;
	}

	public static void main(String[] args)
	{
		String password = "password";
		String data = "testtesttesttesttest14cf21cwcrwcdwacetesttesttesttesttesttest";

		String raw = encrypt(password, data);
		System.out.println(raw);
		String data2 = decrypt(password, raw);
		System.out.println(data2);
	}
}
